/*
 * ============================================================================
 *
 *       Filename:  main.c
 *
 *    Description:  
 *
 *        Version:  1.0
 *        Created:  2014年07月09日 17时29分44秒
 *       Revision:  none
 *       Compiler:  gcc
 *
 *         Author:  jianxi sun (jianxi), ycsunjane@gmail.com
 *   Organization:  
 *
 * ============================================================================
 */
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>  
#include <unistd.h>  
#include <errno.h>
#include <string.h>
#include <sys/types.h>  
#include <sys/stat.h>  
#include <fcntl.h>  
#include <termios.h>  
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include "config.h"
#include "arg.h"

static int set_opt(int fd,int nSpeed, int nBits, char nEvent, int nStop)  
{ 
	struct termios newtio,oldtio;  
	if  ( tcgetattr( fd,&oldtio)  !=  0) {   
		perror("SetupSerial 1");  
		return -1;  
	}  
	bzero( &newtio, sizeof( newtio ) );  
	newtio.c_cflag  |=  CLOCAL | CREAD;  
	newtio.c_cflag &= ~CSIZE;  

	switch( nBits )  
	{  
	case 7:  
		newtio.c_cflag |= CS7;  
		break;  
	case 8:  
		newtio.c_cflag |= CS8;  
		break;  
	}  

	switch( nEvent )  
	{  
	case 'O':  
		newtio.c_cflag |= PARENB;  
		newtio.c_cflag |= PARODD;  
		newtio.c_iflag |= (INPCK | ISTRIP);  
		break;  
	case 'E':   
		newtio.c_iflag |= (INPCK | ISTRIP);  
		newtio.c_cflag |= PARENB;  
		newtio.c_cflag &= ~PARODD;  
		break;  
	case 'N':    
		newtio.c_cflag &= ~PARENB;  
		break;  
	}  

	switch( nSpeed )  
	{  
	case 2400:  
		cfsetispeed(&newtio, B2400);  
		cfsetospeed(&newtio, B2400);  
		break;  
	case 4800:  
		cfsetispeed(&newtio, B4800);  
		cfsetospeed(&newtio, B4800);  
		break;  
	case 9600:  
		cfsetispeed(&newtio, B9600);  
		cfsetospeed(&newtio, B9600);  
		break;  
	case 115200:  
		cfsetispeed(&newtio, B115200);  
		cfsetospeed(&newtio, B115200);  
		break;  
	case 460800:  
		cfsetispeed(&newtio, B460800);  
		cfsetospeed(&newtio, B460800);  
		break;  
	default:  
		cfsetispeed(&newtio, B9600);  
		cfsetospeed(&newtio, B9600);  
		break;  
	}  
	if( nStop == 1 )  
		newtio.c_cflag &=  ~CSTOPB;  
	else if ( nStop == 2 )  
		newtio.c_cflag |=  CSTOPB;  
	newtio.c_cc[VTIME]  = 0;
	newtio.c_cc[VMIN] = 100;
	tcflush(fd,TCIFLUSH);  
	if((tcsetattr(fd,TCSANOW,&newtio))!=0)  
	{  
		perror("com set error");  
		return -1;  
	}  
	return 0;  
}

static in_addr_t r_server(char *dst)
{
	struct hostent *host;
	host = gethostbyname(dst);
	if(host != NULL && host->h_length > 0) {
		fprintf(stderr, "Try connect: %s\n", dst);
		return *(in_addr_t *)host->h_addr_list[0];
	}
	fprintf(stderr, "Can not get: %s\n", dst);
	return 0;
}

int main(int argc, char *argv[])
{
	proc_args(argc, argv);
	if(daemon_mode)
		daemon(0, 0);

	int fd, ret;
	FILE *file;
	fd = open(args_info.dev_arg, O_RDWR);
	if(fd < 0) {
		fprintf(stderr, "open %s failed:%s\n", 
			args_info.dev_arg, 
			strerror(errno));
		exit(-1);
	}

	file = fdopen(fd, "w+");
	if(file == NULL) {
		fprintf(stderr, "get fd FILE ptr failed:%s\n",
			strerror(errno));
		exit(-1);

	}

	ret = set_opt(fd, SPEED, BITS, EVENT, STOP);
	if(ret < 0) {
		fprintf(stderr, "set tty failed:%s\n", 
			strerror(errno));
		exit(-1);
	}

	struct sockaddr_in addr;
	in_addr_t server;
	int serfd;
	serfd = socket(AF_INET, SOCK_DGRAM, 0);
	if(serfd < 0) {
		fprintf(stderr, "Create socket failed: %s(%d)\n", 
			strerror(errno), errno);
		return -1;
	}

	server = r_server(args_info.udpser_arg);
	if(!server) exit(-1);

	addr.sin_family = AF_INET;
	addr.sin_addr.s_addr = server;
	addr.sin_port = htons(args_info.udpport_arg);
	
	char *lineptr = NULL;
	size_t n = 0; 
	while(1) {
		ret = getline(&lineptr, &n, file);
		if(ret < 0) {
			fprintf(stderr, "getline failed: %s(%d)\n",
				strerror(errno), errno);
			exit(-1);
		}

		ret = sendto(serfd, lineptr, ret, 0, (void *)&addr, sizeof(addr));
		if(ret < 0)  {
			fprintf(stderr, "sendto failed: %s(%d)\n",
				strerror(errno), errno);
			exit(-1);
		}

	}
	return 0;
}
